package bbcache

import (
	"context"
	"encoding/json"
	"fmt"
	"longmen/server/config/global"
	"longmen/server/internal/rpc/tencentim/imsdk"
	messages2 "longmen/server/internal/rpc/tencentim/messages"
	"longmen/server/internal/rpc/tencentim/messages/sports"
	"longmen/server/pkg/common/lib/bytesconv"
	"strconv"
	"sync"
	"time"

	"github.com/go-redis/redis"
	"github.com/olivere/elastic/v7"
)

type (
	LineUpCache struct {
		rds redis.UniversalClient
	}
	LineUp struct {
		MatchId      int          `json:"match_id"`       // 比赛ID
		Home         []Player     `json:"home"`           // 主队阵容
		Away         []Player     `json:"away"`           // 客队真人
		HomeTimeLine TimeLineItem `json:"home_time_line"` // 主队在场持续时间统计
		AwayTimeLine TimeLineItem `json:"away_time_line"` // 客队在场持续时间统计
	}
	// ImportantEvents 重要事件
	ImportantEvents struct {
		HomeRecord TimeLineItem `json:"home_record"` // 主队在场持续时间统计
		AwayRecord TimeLineItem `json:"away_record"` // 客队在场持续时间统计
	}

	Player struct {
		Id       int64        `json:"id"`       // 球员id
		NameZh   string       `json:"name_zh"`  // 球员中文名称
		NameZht  string       `json:"name_zht"` // 球员粤语名称
		NameEn   string       `json:"name_en"`  // 球员英文名称
		Logo     string       `json:"logo"`     // 球员logo
		Number   string       `json:"number"`   // 球衣号
		TimeLine TimeLineItem `json:"timeline"` // 在场持续时间统计
	}
	TimeLineItem struct {
		PlayingTime       int `json:"playing_time"`       // 上场时间
		HitCount          int `json:"hit_count"`          // 命中次数
		ShotCount         int `json:"shot_count"`         // 投篮次数
		Goal3Score        int `json:"goal_3_score"`       // 三分球投篮命中次数
		Goal3ScoreCount   int `json:"goal_3_score_count"` // 三分投篮次数
		FQHitCount        int `json:"fq_hit_count"`       // 罚球命中次数
		FQCount           int `json:"fq_count"`           // 罚球投篮次数
		OffensiveRebounds int `json:"offensive_rebounds"` // 进攻篮板
		DefensiveRebounds int `json:"defensive_rebounds"` // 防守篮板
		TotalRebounds     int `json:"total_rebounds"`     // 总的篮板
		Assists           int `json:"assists"`            // 助攻数
		Steals            int `json:"steals"`             // 抢断数
		Caps              int `json:"caps"`               // 盖帽数
		MistakeCount      int `json:"mistake_count"`      // 失误次数
		Fouls             int `json:"fouls"`              // 个人犯规次数
		TotalScore        int `json:"total_score"`        // 总分，计算出来的
	}
)

var (
	lineupInstance *LineUpCache
	lineupOnce     sync.Once
)

const (
	CacheExpire                   = time.Hour * 24 * 7 //保留7天
	BasketBallIndexName           = "basketball_lineup"
	BasketBallIndexLineupCacheKey = "match_live:basketball_lineup:"
	BasketBallIndexEventsCacheKey = "match_live:basketball_lineup_events:"
)

func NewLineUpCache() *LineUpCache {
	lineupOnce.Do(func() {
		lineupInstance = &LineUpCache{
			rds: global.GetRds(),
		}
	})
	return lineupInstance
}

// PublishPlayers 写入篮球阵容缓存
func (l *LineUpCache) PublishPlayers(data LineUp) error {
	lineupMessage := sports.BasketballLineupMessage{
		SentMessageStruct: messages2.SentMessageStruct{Type: messages2.BasketBallLineUpType},
		Lineup:            data,
		Other:             map[string]string{"match_id": strconv.Itoa(data.MatchId)},
	}

	marshal, _ := json.Marshal(lineupMessage)
	msg := string(marshal)
	err := l.rds.Set(l.genLineUpKey(data.MatchId), msg, CacheExpire).Err()
	if err != nil {
		global.Log.Errorf("set cache error: %v", err)
	}
	l.setImportantEvents(data)
	l.segmentBroadcast(data.MatchId, msg)
	return nil
}

// 生成篮球事件
func (l *LineUpCache) genEventsKey(matchId int) string {
	return fmt.Sprintf("%s%d", BasketBallIndexEventsCacheKey, matchId)
}

// 生成篮球阵容Key
func (l *LineUpCache) genLineUpKey(matchId int) string {
	return fmt.Sprintf("%s%d", BasketBallIndexLineupCacheKey, matchId)
}

// 广播重要事件
func (l *LineUpCache) setImportantEvents(data LineUp) {
	events := ImportantEvents{
		HomeRecord: data.HomeTimeLine,
		AwayRecord: data.AwayTimeLine,
	}
	eventMsg := sports.BasketBallLineupEventMessage{
		SentMessageStruct: messages2.SentMessageStruct{Type: messages2.RoomRecordMessageType},
		Record:            events,
	}
	bodyBytes, _ := json.Marshal(eventMsg)
	bodyJson := bytesconv.BytesToString(bodyBytes)
	l.rds.Set(l.genEventsKey(data.MatchId), bodyJson, CacheExpire)
	imsdk.GetSdk().Broadcast(data.MatchId, []string{bodyJson})
}

func (l *LineUpCache) GetEvents(matchId int) string {
	result, err := l.rds.Get(l.genEventsKey(matchId)).Result()
	if err != nil {
		return ""
	}
	return result
}

// segmentBroadcast 分批次推送
// 腾讯的接口有大小限制，需要分段推送
func (l *LineUpCache) segmentBroadcast(matchId int, msg string) {
	sLen := len(msg)
	split := 3 //和客户端约定分成三段

	for i := 0; i < split; i++ {
		var lineupRsp sports.LineupResp
		lineupRsp.Type = fmt.Sprint("lineupLive-", i+1)
		if i == 2 {
			lineupRsp.Lineup = msg[i*sLen/split:]
		} else {
			lineupRsp.Lineup = msg[i*sLen/split : (i+1)*sLen/split]
		}
		m, err := json.Marshal(lineupRsp)
		if err != nil {
			global.Log.Errorf("basketball TeamRecord marshal err : %v, room_id : %v", err, matchId)
		}

		//global.Log.Debugf("send TeamRecord Rsp : %+v", string(m))
		imsdk.GetSdk().Broadcast(matchId, []string{string(m)})
	}
}

// GetLineUpCache 获取缓存
func (l *LineUpCache) GetLineUpCache(matchId int) string {
	result, err := l.rds.Get(l.genLineUpKey(matchId)).Result()
	if err != nil {
		return ""
	}
	return result
}

func (l *LineUpCache) GetLineForEs(matchId int) string {
	searchResult, err := global.GetEs().Search().Index(BasketBallIndexName).Query(elastic.NewTermQuery("line_up.match_id", matchId)).Size(1).Do(context.Background())
	if err != nil {
		global.Log.Errorf("err", err)
		return ""
	}
	if searchResult.Hits.TotalHits.Value > 0 {
		hit := searchResult.Hits.Hits[0]
		jsonData, err := json.Marshal(hit.Source)
		if err != nil {
			global.Log.Errorf("err", err)
			return ""
		}
		return string(jsonData)
	}
	return ""
}

// WriteToEs 写进es
func (l *LineUpCache) WriteToEs(cacheKey string) bool {
	global.Log.Debugf("key:%s", cacheKey)
	ttl, err := l.rds.TTL(cacheKey).Result()
	if err != nil {
		global.Log.Errorf("err:%v", err)
		return false
	}
	global.Log.Debugf("ttl:%v", ttl.Seconds())
	if ttl.Seconds() > 3600 {

		return false
	}
	result, err := l.rds.Get(cacheKey).Result()
	if err != nil {
		global.Log.Errorf("err:%v", err)
		return false
	}
	_, err = global.GetEs().Index().Index(BasketBallIndexName).BodyJson(result).Do(context.Background())
	if err != nil {
		global.Log.Errorf("err:%v", err)
		return false
	}
	err = l.rds.Del(cacheKey).Err()
	if err != nil {
		global.Log.Errorf("err:%v", err)
	}
	return true
}

func (l *LineUpCache) GetAllLineUp() []string {
	//r, err := l.rds.Keys(BasketBallIndexCacheKey + "*").Result()
	//if err != nil {
	//	global.Log.Errorf("err:%v", err)
	//	return []string{}
	//}
	//return r
	key := BasketBallIndexLineupCacheKey + "*"
	var resp []string
	var cursor uint64
	for {
		var err error
		var rs []string
		rs, newCursor, err := l.rds.Scan(cursor, key, 200).Result()
		if err != nil {
			global.Log.Errorf("GetAllLineUp err:%v,cursor:%v,:rs:%v", err, cursor, rs)
			break
		}
		for k, v := range rs {
			if k%2 != 0 {
				resp = append(resp, v)
			}
		}
		if newCursor == 0 {
			break
		}
		cursor = newCursor
	}
	global.Log.Debugf("篮球阵容同步长度:%v", len(resp))
	return resp

}
